Функциональные возможности
Печать
Штамп
Конвертация
Печать
В режиме печати происходит получения шаблона и json из входных данных.
возможна обработка двух типов docx и html
Будем рассматривать на примере шаблона docx.
Заполнение
шаблонного документа docx формата данными из json формата. значения
заключенные в двойные фигурные скобки внутри docx заменяются на
соответствующие значения из json
Пример:
Тело docx документа
Директору ООО Шайки-лейкиот {{document.applicant.lastName}} {{document.applicant.firstName}} {{document.applicant.middleName}}жалоба.Доношу до вашего сведения информацию об отвратительном состоянии инвентаря в бане № {{document.subject_number}}Полки не мыты. Полы залиты. Крайне недоволен. Исправьте ситуацию.{{document.date}} {{document.applicant.shortFIO}} |
Данные в виде json
{ "document": { "applicant": { "firstName": "Иван", "lastName": "Иванов", "middleName": "Иванович" }, "subject_number": 4, "shortFIO":"Иванов И. И.", "date":"03.01.2023" }} |
Штамп
в режиме штамп на входящий документ накладывается дополнительный текст, а также сформированное изображение из сертификата, которое отражает инициалы подписавшего и срок действия сертификата
Возможные типы входящих документов для версии 2.0.0
pdf, docx
Штамп успешно накладывается и регулируется входными и параметрами настройки в случае,
если контент внутри документа является текстовым.
Если внутри документа содержится изображение масштабированное на весь лист (например скан), то для такого документа корректное наложение штампа не предусмотрено.
Параметры для наложения штампа на документ следующие
certificate - Сертификат подписанта в Base64
s3url - ссылка на s3, например s3://bucket/templateResolution-b559615a-af21-417f-9a63-e5f6eca42342.docx
stampWidth - ширина штампа в пикселях (если не указано, то по умолчанию 220)
stampHeight - высота штампа в пикселях (если не указано, то по умолчанию 85)
stampAlign - размещение штампа на странице (если не указано, по умолчанию справа [LEFT/RIGHT])
rightText - Текст для вывода слева от штампа
leftText - Текст для вывода слева от штампа
pageNumber - Номер страницы для печати (Последняя страница по дефолту)
leftMargin - Отступ от левого края для текста слева страницы (в символах)
rightMargin - Отступ от правого края для текста справа страницы (в символах)
Также предусмотрен функционал совместной последовательной печати и штампа.
Конвертация
Под конвертацией понимается преобразование одного типа документа в другой.
В данный момент возможны следующие направления конвертации:
HTML → PDF
HTML → DOCX
DOCX → PDF
В любом из функциональных возможностей обязательно указание направление конвертации
в виде двух параметров
inputFormat
outputFormat
inputFormat для функционала Печать также позволяет определить тип передаваемого шаблона
outputFormat указывает в какой тип файла будет в результате.
Если указанные параметры конвертации будут указаны неверно, то возникает ошибка с указанием о этом.
Режимы работы
Кафка
В режиме работы через kafka, выполняется разбор сообщений поступающих в топики
printer.process.print - функционала печати
printer.process.stamp - функционал штампа
printer.process.print-stamp - функционал последовательного применения печати и штампа
Выполняется функциональное действие соответствующее каждому топику
Результат в виде готового файла размещается в хранилище s3, ссылка на результат прикладывается в отчет о выполнении.
Сам отчет в виде сообщения кафки публикуется в топик printer.report
Функционалы печать, штамп, печать+штамп можно включить или выключить в зависимости от настроек экземпляра сервиса, которые требуются для него.
При масштабирования сервиса, возможна конкуренция за вычитку сообщений из топиков, поэтому для каждого экземпляра назначается свой consumer-group-id, на основе переменной окружения POD_NAME.
Также добавлена возможность идемпотентной обработки (MODE_KAFKA_IDEMPOTENCY), для избежания дублирующих заданий на печать/штамп с последующим результатом в s3 и топик printer.report
Предусмотрен таймаут выполнения одного задания при работе через kafka (KAFKA_PRINT_TASK_EXECUTION=4m)
HTTP REST
В этом варианте присутствуют два режима обработки, синхронный и асинхронный.
В синхронном режиме входными параметрами являются шаблон и json-параметры для функционала печати,
для функционала штампа документ и параметры штампа.
Запрос блокируются до окончания выполнения и получения готового документа либо ошибки во время выполнения.
В асинхронном режиме, проверяется направление конвертации, затем параллельно запускается обработка задания на печать (наложение штампа)
Если конвертация не поддерживается то сразу возвращается ошибка о неприменимости такого действия (http 406)
По окончании задания на печать формируется отчет в топик кафки printer.report
Возможно прямое перенаправление асинхронных запросов в топики кафки. (MODE_REST_KAFKA_REDIRECT)
Предполагается, что это предотвратит потерю результата в момент рестарта сервиса и не законченном задании на печать.
Конечные точки
/normalize
Очищает плейсхолдеры в docx шаблоне от форматирования синхронно.
Ворд может разбивать текст на отдельные блоки форматирования, ломая mustache.
Метод вырезает все xml-теги между фигурными скобками, присваивая стиль всему плейсхолдеру, как у открывающейся скобки.
/sync/{input}/to/{output}
Печатает шаблон синхронно в указанном формате (input) и конвертирует его в указанный формат (output), немедленно возвращает распечатанный документ как файл в http ответе
/stamp/sync/{input}/to/{output}
Добавляет
штамп в документ синхронно в указанном формате (input) и конвертирует
его в указанный формат (output), немедленно возвращает распечатанный
документ как файл в http ответе
/sync/stamp-print/{input}/to/{output}
Печатает
шаблон синхронно в указанном формате (input), накладывает штамп и
конвертирует его в указанный формат (output), немедленно возвращает
распечатанный документ как файл в http ответе
/async/{input}/to/{output}
Принимает шаблон в асинхронную печать
/stamp/async/{input}/to/{output}
Принимает
документ для асинхронной печати штампа в указанном формате (input) и
конвертирует его в указанный формат (output) и отсылает сообщение о
статусе печати вместе с ссылкой на скачивание из S3 в Kafka Topic
/async/stamp-print/{input}/to/{output}
Принимает
шаблон в асинхронную печать в указанном формате (input), накладывает
штамп и конвертирует его в указанный формат (output) и отсылает
сообщение о статусе печати вместе с ссылкой на скачивание из S3 в Kafka
Topic
/selftest
самодиагностика сервиса
возращает результат проверки функциональных возможностей
{
docxPrint: SUCCESS,
htmlPrint: SUCCESS,
pdfStamp: SUCCESS,
docxStamp: SUCCESS,
htmlStampAfterPrint: SUCCESS,
docxStampAfterPrint: SUCCESS
}
/swagger-ui
Доступен сваггер c описанием REST-методов
/health
Проверка работоспособности сервиса от micronaut
/prometheus
Точка предоставления метрик для Prometheus
Настройки
micronaut: application: name: printer default-charset: UTF-8 server: port: ${SERVICE_PORT:8080} metrics: enabled: true export: prometheus: enabled: true step: PT1M descriptions: true heartbeat: enabled: false health: monitor: enabled: true router: static-resources: swagger-ui: paths: classpath:/swagger-ui mapping: /swagger-ui/** security: enabled: ${SECURITY_ENABLED:true} # вкл\выкл безопасности token: enabled: true # включаем token-based безопасность jwt: enabled: true bearer: enabled: truelogger: levels: root: ${PRINT_LOG_LEVEL:INFO} sx.microservices: ${SX_LOG_LEVEL:INFO}s3: enabled: ${AWS_S3_ENABLED:true} url: ${AWS_ENDPOINT:`http://localhost:9011`} urlExternal: ${AWS_ENDPOINT_EXTERNAL:`http://localhost:9011`} key: ${AWS_ACCESS_KEY_ID:} secret: ${AWS_SECRET_ACCESS_KEY:} bucket: ${AWS_S3_BUCKET:printed-documents} bucket-suffix-enabled: ${AWS_S3_BUCKET_SUFFIX_ENABLED:false} bucket-create-if-not-exist: ${AWS_S3_BUCKET_CREATE_IF_NOT_EXIST:true} url-expire-in-seconds: ${AWS_S3_URL_EXPIRE_SECONDS:604800} url-presigned-enabled: ${AWS_S3_URL_PRESIGNED_ENABLED:true} health: enabled: ${AWS_S3_HEALTH_ENABLED:true} timeout: ${AWS_S3_HEALTH_TIMEOUT:3000ms} retries: ${AWS_S3_HEALTH_RETRIES:2}redis: uri: ${REDIS_CONNECTION_STRING:`redis://localhost`} caches: print-processing-cache: expire-after-write: 2h stamp-processing-cache: expire-after-write: 2hswagger: merge-files: false sso-endpoint: ${SSO_CLIENT_URL_HOST:`https://pgs2-uat-sso.test.gosuslugi.ru`}#Настройки режима работы экземпляра сервисаmode: #Режим работы через кафка kafka: enabled: true #Обработка заполнения шаблона, с последующей конвертацией print: enabled: true #Обработка подписания (наложения штампа подписанта) stamp: enabled: true #Обработка заполнения шаблона, затем наложения штампа print-stamp: enabled: true #Вкючить режим идемпотентной обработки сообщений idempotency: true #Режим работы через REST rest: enabled: true #перенаправлять асинхроные запросы в kafka топики kafka-redirect: trueprinter-topics: report: ${KAFKA_TOPIC_PREFIX:}printer.report print-consumer: ${KAFKA_TOPIC_PREFIX:}printer.process.print stamp-consumer: ${KAFKA_TOPIC_PREFIX:}printer.process.stamp print-stamp-consumer: ${KAFKA_TOPIC_PREFIX:}printer.process.print-stampkafka: group-id-prefix: ${KAFKA_GROUP_PREFIX:} group-id-suffix: _${POD_NAME:} bootstrap: servers: ${KAFKA_HOSTS:`localhost:9092,localhost:9093,localhost:9094`} health: enabled: ${KAFKA_ENABLED:true} producers: default: retries: 3 health-timeout: 4500ms max: poll: records: 500 interval: ms: 300000 #Таймаут на выполнение одного задания на печать, при работе через кафка print-task-execution: 4msecure-configuration: token-validation: enabled: true trusted-issuers: ${TRUSTED_ISSUERS:} scopes: - printer userinfo-roles: enabled: true path: /userinfo# Конфигурация библиотеки client-token-managertoken-manager: enabled: true # В случае невозможности использовать автоматическую конфигурацию OIDC, тут указывается Token Endpoint. token-endpoint: ${SSO_CLIENT_URL_HOST:`http://sso-service`}/token # Зарегистрированный client_id. client-id: ${SSO_CLIENT:printer-client} # Зарегистрированный client_secret. client-secret: ${SSO_CLIENT_SECRET:93456662-5e0c-4ea1-883c-fd6be4c82d29} # Необходимые для работы приложения скоупы. scope: openid,ClientScope1,service # За сколько секунд до окончания времени жизни токена нужно будет получить новый. По умолчанию 15 секунд. token-expires-in-skew: ${SSO_CLIENT_REFRESH_TOKEN_BEFORE:60s}jackson: date-format: yyyy-MM-dd'T'HH:mm:ss.SSSXXXendpoints: loggers: enabled: true health: enabled: true sensitive: false details-visible: ANONYMOUS # show details for everyone metrics: enabled: false sensitive: true prometheus: enabled: true sensitive: falsetracing: jaeger: enabled: ${JAEGER_ENABLED:false} exclude-paths: - /health - /prometheus - /favicon.ico - /api - /swagger-ui sampler: probability: ${JAEGER_SAMPLER_PROBABILITY:1} sender: agentHost: ${JAEGER_HOST:localhost} agentPort: ${JAEGER_PORT:6831}libreoffice: enabled: ${LIBREOFFICE_ENABLED:true} office-home: /usr/lib/libreoffice portNumbers: 8105,8104,8103,8102,8101 maxTasksPerProcess: 100 taskExecutionTimeout: 30000 process-timeout: 5000 startFailFast: true remote: enabled: false connectTimeout: 60000 # минута socketTimeout: 12000 # 2 минуты poolSize: 1#Предпочтения конвертеровconverters: #input html: #output pdf: - HtmlToPdfLibreOfficeConverter - OpenHtmlToPdfConverter - WkHtmlToPdfConverter - SauseHtmlToPdfConverter docx: - HtmlToDocxLibreOfficeConverter - HtmlToDocxConverter #input docx: #output pdf: - DocxToPdfLibreOfficeConverter - ApacheDocxToPdfConverter |
Журналирование
Логирование в json формате включается переменной окружения JSON_ENABLE=true
Уровень логирования указывается в переменной окружения PRINT_LOG_LEVEL=INFO (ERROR,INFO,DEBUG)
Необходимые ресурсы окружения сервиса
sso
переменная окружения TOKEN_MANAGER_TOKEN_ENDPOINT
kafka
переменная окружения KAFKA_HOSTS
redis
переменная окружения REDIS_CONNECTION_STRING
s3
переменные окружения
AWS_ENDPOINT
AWS_ENDPOINT_EXTERNAL
jaeger
переменные окружения
JAEGER_HOST
JAEGER_PORT
kubernetess
Для старта приложения требуется примерно от 15 до 30 секунд, поэтому стартап проба должна быть от этих значений.
Для остальных проб(readiness,liveness) нужно использовать подготовленный внутри образа скрипт
/readiness.sh
В случае успешной проверки он возвращает exit_code=0 иначе exit_code>0
Внутри скрипта выполняются проверки на соответствие
количества экземпляров libreOffice запущенных сейчас с количеством указанных в настройках при старте экземпляра сервиса.
затем проверка на доступность http, так как он также является индикатором для успешного старта экземпляра сервиса
Мониторинг
Предусматривает несколько графиков регистрирующих количество запросов функционала (печать,штамп,штамп+печать) и количество ответов, по одному на каждый функционал
Также на каждый функционал имеются графики с ошибками. Их два: первый в разрезе направления конвертации, второй детальный по тексту ошибки и экземплярам сервисов.
Метрики которые реализованы для экспорта в Prometheus (являются счетчиками)
printRequest
stampRequest
printStampRequest
printCompleted
stampCompleted
printStampCompleted
printError
stampError
printStampError
для всех метрик добавляются следующие теги
from, to, fileName
traceId, podName
для режима работы через кафку также добавляется тэг kafka=true
в режиме обработки через кафку также добавляется тэг retryCount, если он присутствовал в заголовке исходного сообщения кафки.
retryCount ( счетчик повторов для одного задания на печать/штамп)
для метрик с суффиксом Error, добавляется тэг duration и error (с текстом ошибки)
для метрик с суффиксом Completed, добавляется также тэг duration (время в секундах прошедшее с начала обработки задания печати/штампа)
Примеры:
Формирование заявления
Для формирования используется шаблон template_HuntingResourcesResult_0_2.docx и данные json из файла HuntingResourcesResult_0_2.json
curl -X POST https://pgs2-uat.test.gosuslugi.ru/service/printer/sync/DOCX/to/DOCX \-H 'Authorization: Bearer eyJraWQiOiJzc29rZXkxIiwidHlwIjoiSldUIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIyMmRlYTM0MS1mNWU0LTRiOGMtOGU4My05NDMxZDQwMzdkOTIiLCJhbXIiOlsiSURQX0xPQ0FMIl0sInJvbGVzIjpbItCR0LDQt9C-0LLQsNGPINGA0L7Qu9GMINC00LvRjyDQsNCy0YLQvtGA0LjQt9Cw0YbQuNC4Iiwi0J_QvtC70YzQt9C-0LLQsNGC0LXQu9GM0YHQutCw0Y8g0YDQvtC70YwiLCLQoNC10LPQuNGB0YLRgNCw0YLQvtGAIiwi0J3QsNC30L3QsNGH0LDRjtGJ0LjQuSDRgNC10LPQuNGB0YLRgNCw0YLQvtGAIiwi0KHQv9C10YbQuNCw0LvQuNGB0YIiLCLQlNC-0LvQttC90L7RgdGC0L3QvtC1INC70LjRhtC-INGBINC_0L7QtNC_0LjRgdGM0Y4iLCLQndCw0LfQvdCw0YfQsNGO0YnQuNC5INGB0L_QtdGG0LjQsNC70LjRgdGCIiwicHJlb3JkZXJfYWRtaW4iLCJzZXJ2aWNlc0NvbnN0cnVjdCIsIlMzQ2xpZW50IiwicGVyc29uYWxSZWNlcHRpb24iXSwiaXNzIjoiaHR0cHM6XC9cL3BnczItdWF0LXNzby50ZXN0Lmdvc3VzbHVnaS5ydSIsImdyb3VwcyI6W10sImRvbWFpbl9pZCI6IjZiNTdmYmY3LTc5MTAtNGQwNy1iNmU3LTQ3YmU5YjlhZjVkZSIsImF1ZCI6ImFybSIsImFjY291bnRJZCI6IjIyZGVhMzQxLWY1ZTQtNGI4Yy04ZTgzLTk0MzFkNDAzN2Q5MiIsIm5iZiI6MCwiYXpwIjoiYXJtIiwiYXV0aF90aW1lIjowLCJuYW1lIjoi0JzQvtC70L7QutC-0LLRgdC60LjRhSDQodC10YDQs9C10LkiLCJyZWFsbSI6IkZpcm1hIG1vZGEiLCJleHAiOjE2Nzg5NTE4MzcsInNlc3Npb25fc3RhdGUiOiI3ZmQ2YWE3OS1mNDg1LTQ0YTctOTM4Ny1lYTAyMDhkMDZlMjEiLCJpYXQiOjE2Nzg5NDgyMzd9.IU1EuZ3Uh8PuZjmkUBktzesiZlU7PilAICuZM6-tKaZq7qS6NmC6tK5-4s5BWPm5BFpE2VkMlzOnBzFVnikjGzKcQ2QY40j8L6kEgUADN6jzE3xpQyI_IGnppFXpkurVgeHUlF2jKFTXrAZpektFClbqDmqYJM4nEvp7HGbLjurFixX23v8EcS5HIIN97lhTJaHqzir1keg427W4FhGL4f9sxkbXWenBDkMxDQA0lzWgNZeFL5khSNgPUr9ovIiHN_CmuKQy3gkS756k7QNe75LANdXd-Chaziz7M4Qmjjv6MM1CGSaPhOrqeVsUZI9cKeCFBlTLGfsxVCXuk_dG6w' \-H 'Content-Type: multipart/form-data' \-F 'template=@template_HuntingResourcesResult_0_2.docx' \-F 'parameters=@HuntingResourcesResult_0_2.json' \-o HuntingResourcesResult_0_2.docx |
Формирование межведомственного запроса
Для формирования используется шаблон template_EGRUL-INN.html и данные json
curl -X POST https://pgs2-uat.test.gosuslugi.ru/service/printer/sync/stamp-print/HTML/to/PDF \-H 'Authorization: Bearer eyJraWQiOiJzc29rZXkxIiwidHlwIjoiSldUIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiIyMmRlYTM0MS1mNWU0LTRiOGMtOGU4My05NDMxZDQwMzdkOTIiLCJhbXIiOlsiSURQX0xPQ0FMIl0sInJvbGVzIjpbItCR0LDQt9C-0LLQsNGPINGA0L7Qu9GMINC00LvRjyDQsNCy0YLQvtGA0LjQt9Cw0YbQuNC4Iiwi0J_QvtC70YzQt9C-0LLQsNGC0LXQu9GM0YHQutCw0Y8g0YDQvtC70YwiLCLQoNC10LPQuNGB0YLRgNCw0YLQvtGAIiwi0J3QsNC30L3QsNGH0LDRjtGJ0LjQuSDRgNC10LPQuNGB0YLRgNCw0YLQvtGAIiwi0KHQv9C10YbQuNCw0LvQuNGB0YIiLCLQlNC-0LvQttC90L7RgdGC0L3QvtC1INC70LjRhtC-INGBINC_0L7QtNC_0LjRgdGM0Y4iLCLQndCw0LfQvdCw0YfQsNGO0YnQuNC5INGB0L_QtdGG0LjQsNC70LjRgdGCIiwicHJlb3JkZXJfYWRtaW4iLCJzZXJ2aWNlc0NvbnN0cnVjdCIsIlMzQ2xpZW50IiwicGVyc29uYWxSZWNlcHRpb24iXSwiaXNzIjoiaHR0cHM6XC9cL3BnczItdWF0LXNzby50ZXN0Lmdvc3VzbHVnaS5ydSIsImdyb3VwcyI6W10sImRvbWFpbl9pZCI6IjZiNTdmYmY3LTc5MTAtNGQwNy1iNmU3LTQ3YmU5YjlhZjVkZSIsImF1ZCI6ImFybSIsImFjY291bnRJZCI6IjIyZGVhMzQxLWY1ZTQtNGI4Yy04ZTgzLTk0MzFkNDAzN2Q5MiIsIm5iZiI6MCwiYXpwIjoiYXJtIiwiYXV0aF90aW1lIjowLCJuYW1lIjoi0JzQvtC70L7QutC-0LLRgdC60LjRhSDQodC10YDQs9C10LkiLCJyZWFsbSI6IkZpcm1hIG1vZGEiLCJleHAiOjE2Nzg5NTE4MzcsInNlc3Npb25fc3RhdGUiOiI3ZmQ2YWE3OS1mNDg1LTQ0YTctOTM4Ny1lYTAyMDhkMDZlMjEiLCJpYXQiOjE2Nzg5NDgyMzd9.IU1EuZ3Uh8PuZjmkUBktzesiZlU7PilAICuZM6-tKaZq7qS6NmC6tK5-4s5BWPm5BFpE2VkMlzOnBzFVnikjGzKcQ2QY40j8L6kEgUADN6jzE3xpQyI_IGnppFXpkurVgeHUlF2jKFTXrAZpektFClbqDmqYJM4nEvp7HGbLjurFixX23v8EcS5HIIN97lhTJaHqzir1keg427W4FhGL4f9sxkbXWenBDkMxDQA0lzWgNZeFL5khSNgPUr9ovIiHN_CmuKQy3gkS756k7QNe75LANdXd-Chaziz7M4Qmjjv6MM1CGSaPhOrqeVsUZI9cKeCFBlTLGfsxVCXuk_dG6w' \-H 'Content-Type: multipart/form-data' \-F 'template=@template_EGRUL-INN.html' \-F 'parameters={ "rightText": "Текст справа", "leftText": "Текст слева", "certificate": "MIIDtDCCA2OgAwIBAgITEgBfwqhLIsIXlM6p7QABAF/CqDAIBgYqhQMCAgMwfzEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBjcnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJVMQ8wDQYDVQQHEwZNb3Njb3cxFzAVBgNVBAoTDkNSWVBUTy1QUk8gTExDMSEwHwYDVQQDExhDUllQVE8tUFJPIFRlc3QgQ2VudGVyIDIwHhcNMjIwOTE1MTI0NjQzWhcNMjIxMjE1MTI1NjQzWjCBuDEvMC0GA1UEAwwm0J/QvtC/0L7QstCwINCQ0L3QvdCwINCY0LPQvtGA0LXQstC90LAxgYQwgYEGA1UECgx60JfQsNC80LXRgdGC0LjRgtC10LvRjCDQvdCw0YfQsNC70YzQvdC40LrQsCDRg9C/0YDQsNCy0LvQtdC90LjRjywg0L3QsNGH0LDQu9GM0L3QuNC6INC+0YLQtNC10LvQsCDQs9GA0LDQtNC+0YHRgtGA0L7QuNGC0LUwZjAfBggqhQMHAQEBATATBgcqhQMCAiQABggqhQMHAQECAgNDAARAtygzTSOENmXekFekmqaKLZPQ42aWGrrbz19ogYGRuNr28PeGIdZL43/RjY76a00y60vztnCuiApZprMhrRZXqKOCAXcwggFzMA8GA1UdDwEB/wQFAwMH8AAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFK1se3cYcP9GAMyZtrksajRC2uU7MB8GA1UdIwQYMBaAFE6DPhRp7+xdepUrXxH+NzIWSVUrMFwGA1UdHwRVMFMwUaBPoE2GS2h0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJvLnJ1L0NlcnRFbnJvbGwvQ1JZUFRPLVBSTyUyMFRlc3QlMjBDZW50ZXIlMjAyKDEpLmNybDCBrAYIKwYBBQUHAQEEgZ8wgZwwZAYIKwYBBQUHMAKGWGh0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJvLnJ1L0NlcnRFbnJvbGwvdGVzdC1jYS0yMDE0X0NSWVBUTy1QUk8lMjBUZXN0JTIwQ2VudGVyJTIwMigxKS5jcnQwNAYIKwYBBQUHMAGGKGh0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJvLnJ1L29jc3Avb2NzcC5zcmYwCAYGKoUDAgIDA0EAsdDYX/XEtjJ/YtqnJT/Ip5oHZUPfDbJb8bRMh4s4xabl62dHxhdi1rmSm5G+87y7zCcdOvM7VsYABdzwn5WjeA=="}' \-o EGRUL-INN.pdf |
Добавить комментарий